﻿// ------------------------------------------------------------------------
// 项目名称：Canroc.Net 
// 版权归属：Canroc（https://gitee.com/canroc）
//
// 许可证信息
// Canroc.Net项目主要遵循 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-APACHE 文件。
//
// 使用条款：
// 1.使用本项目应遵守相关法律法规和许可证的要求。
// 2.不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。
// 3.任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任
//
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
//
// 其他重要信息
// Canroc.Net 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// ------------------------------------------------------------------------

using Canroc.Net.Application.SysRoleService.Dto;

// ReSharper disable once CheckNamespace
namespace Canroc.Net.Application.SysRoleService;

/// <summary>
///     系统角色应用服务
/// </summary>
[ApiDescriptionSettings("System")]
// ReSharper disable once PartialTypeWithSinglePart
public partial class SysRoleAppService(
    SqlSugarRepository<SysRole> roleRep,
    SqlSugarRepository<RelRoleMenu> roleAndMenuRep,
    SqlSugarRepository<RelRoleResource> roleAndResource) : IDynamicApiController, ITransient
{
    /// <summary>
    ///     添加系统角色
    /// </summary>
    /// <param name="data">表单数据</param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task<bool> AdditionAsync(RoleInput data)
    {
        var entity = data.Adapt<SysRole>();
        entity.Id = Guid.NewGuid();

        List<RelRoleMenu> menuList = [];
        data.MenuIds?.ForEach(menuId =>
        {
            menuList.Add(new RelRoleMenu { RoleId = entity.Id, MenuId = menuId });
        });

        // 数据库写操作
        await roleRep.InsertAsync(entity);
        _ = menuList.Count > 0 && await roleAndMenuRep.InsertRangeAsync(menuList);

        return true;
    }

    /// <summary>
    ///     编辑系统角色
    /// </summary>
    /// <param name="data">表单数据</param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task<bool> EditAsync(RoleInput data)
    {
        var entity = await roleRep.GetByIdAsync(data.Id);
        // 更新数据
        data.Adapt(entity);

        List<RelRoleMenu> menuList = [];
        data.MenuIds?.ForEach(menuId =>
        {
            menuList.Add(new RelRoleMenu { RoleId = entity.Id, MenuId = menuId });
        });

        // 数据库写操作
        _ = await roleRep.UpdateAsync(entity);
        _ = await roleAndMenuRep.DeleteAsync(r => r.RoleId == entity.Id);
        _ = menuList.Count > 0 && await roleAndMenuRep.InsertRangeAsync(menuList);

        return true;
    }

    /// <summary>
    ///     编辑系统角色状态
    /// </summary>
    /// <param name="data">请求参数</param>
    /// <returns></returns>
    public async Task<bool> EnableAsync(InputModel data)
    {
        return await roleRep.UpdateAsync(r => new SysRole { IsEnable = SqlFunc.IIF(r.IsEnable, false, true) },
            r => r.Id == data.Id);
    }

    /// <summary>
    ///     删除系统角色
    /// </summary>
    /// <param name="data">请求参数</param>
    /// <returns></returns>
    public async Task<bool> DelAsync(DeleteInputModel data)
    {
        return await roleRep.UpdateAsync(r => new SysRole { IsDelete = true }, r => data.Ids.Contains(r.Id));
    }

    /// <summary>
    ///     分配角色资源
    /// </summary>
    /// <param name="data">请求参数</param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task<bool> DistributionResourceAsync(RoleDistributionResourceInput data)
    {
        List<RelRoleResource> irr = [];
        data.Routes.ForEach(route =>
        {
            irr.Add(new RelRoleResource { RoleId = data.Id, Route = route });
        });

        _ = await roleAndResource.DeleteAsync(r => r.RoleId == data.Id);
        return irr.Count > 0 && await roleAndResource.InsertRangeAsync(irr);
    }

    /// <summary>
    ///     获取系统角色
    /// </summary>
    /// <param name="id">主键</param>
    /// <returns></returns>
    public async Task<RoleOutput?> GetDataAsync(Guid id)
    {
        return await roleRep
            .AsQueryable()
            .Where(r => r.Id == id)
            .Select(
                r => new RoleOutput
                {
                    MenuIds = SqlFunc.Subqueryable<RelRoleMenu>().Where(iru => iru.RoleId == r.Id)
                        .ToList(iru => iru.MenuId)
                }, true)
            .FirstAsync();
    }

    /// <summary>
    ///     获取角色已拥有的菜单集合
    /// </summary>
    /// <param name="id">角色Id</param>
    /// <returns></returns>
    public async Task<List<Guid>?> GetRoleMenuAsync(Guid id)
    {
        return await roleAndMenuRep.AsQueryable().Where(i => i.RoleId == id).Select(i => i.MenuId).ToListAsync();
    }

    /// <summary>
    ///     获取角色已分配的资源
    /// </summary>
    /// <param name="id">角色Id</param>
    /// <returns></returns>
    public async Task<List<string>?> GetRoleResourceAsync(Guid id)
    {
        return await roleAndResource.AsQueryable().Where(r => r.RoleId == id).Select(r => r.Route)
            .ToListAsync();
    }

    /// <summary>
    ///     分页: 系统角色集合
    /// </summary>
    /// <param name="query">请求参数</param>
    /// <returns></returns>
    public async Task<PageModel<RoleOutput>> GetPageAsync([FromQuery] RolePageQuery query)
    {
        return await roleRep
            .AsQueryable()
            .Where(r => r.Code != "root")
            .WhereIF(!query.Name.IsNullOrEmpty(), r => r.Name.Contains(query.Name))
            .WhereIF(query.IsEnable.HasValue, r => r.IsEnable == query.IsEnable)
            .OrderByPropertyName(query.OrderField, query.IsAscending ? OrderByType.Asc : OrderByType.Desc)
            .Select<RoleOutput>()
            .ToPageAsync(query.PageIndex, query.PageSize);
    }

    /// <summary>
    ///     获取系统角色下拉选项
    /// </summary>
    /// <returns></returns>
    public async Task<List<SelectOptionOutputModel>?> GetSelectOptionAsync()
    {
        return await roleRep
            .AsQueryable()
            .Where(r => r.Code != "root" && r.IsEnable)
            .OrderBy(r => r.CreateTime)
            .Select(r => new SelectOptionOutputModel { Label = r.Name, Value = r.Id })
            .ToListAsync();
    }

    #region 内部函数

    /// <summary>
    ///     获取角色已分配的资源
    /// </summary>
    /// <param name="roleIds">角色Id集合</param>
    /// <returns></returns>
    [NonAction]
    public async Task<List<string>?> GetRoleResourceAsync(List<Guid> roleIds)
    {
        return await roleAndResource.AsQueryable().Where(r => roleIds.Contains(r.RoleId)).Distinct()
            .Select(r => r.Route).ToListAsync();
    }

    #endregion
}